import * as express from "express";
import { ControllerMetadata, ControllerMethodMetadata, ControllerRouteInfo, IController } from "./interfaces";
import { METADATA_KEY } from "./constants";
import { pipe, curry, filter, isNil, tap } from 'ramda';
const { map } = require('pointfree-fantasy');
const { Just, Nothing } = require('data.maybe');

/**
 * getMetadata :: controller -> {controllerMetadata, methodMetadata}
 * @param {IController} controller - instance of Controller
 * @returns {{controllerMetadata: ControllerMetadata, methodMetadata: ControllerMethodMetadata}}
 */
function getMetadata(controller: IController) {
    const controllerMetadata = Reflect.getOwnMetadata(
        METADATA_KEY.controller,
        controller.constructor
    );

    const methodMetadata = Reflect.getOwnMetadata(
        METADATA_KEY.controllerMethod,
        controller.constructor
    );

    return (controllerMetadata && methodMetadata)
        ? { controllerMetadata, methodMetadata }
        : undefined;
}

function getControllerRouteInfo({ controller, metadata }): ControllerRouteInfo {
    const { controllerMetadata, methodMetadata } = metadata;
    return Object.assign(controllerMetadata, { methods: methodMetadata });
}

// getControllerRouteInfos :: [Controller] -> [{path, middleware, target, methods}]
export const getControllerRouteInfos = pipe<any, any, any, any, ControllerRouteInfo[]>(
    map(Controller => new Controller()),
    map(controller => ({ controller: controller, metadata: getMetadata(controller) })),
    filter((x: any) => x.metadata),
    map(getControllerRouteInfo)
);
